#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>

const int gcap = 5;

template <class T>
class queue_block
{
public:
    queue_block(const int cap = gcap)
    :_cap(cap)
    {
        pthread_mutex_init(&mutex,nullptr);
        pthread_cond_init(&_consumerCond,nullptr);
        pthread_cond_init(&_productorCond,nullptr);
    }

    int isfull()
    {
        return _q.size() == _cap;
    }
    int isempty()
    {
        return _q.empty();
    }

    void push(const T &in)
    {
        pthread_mutex_lock(&mutex);//加锁

        while(isfull())//货架满，生产者等待
        {
            pthread_cond_wait(&_productorCond,&mutex);
        }
        //有空余空间，生产者可继续生产
        _q.push(in);
        //一定有商品，唤醒消费者

        //......
        //这里可以加唤醒策略，例如生产者生产的数量超过空间的一半
        // if(_q.size() > _cap/2)
        pthread_cond_signal(&_consumerCond);

        pthread_mutex_unlock(&mutex);//解锁


    }

    void pop(T *out)
    {
        pthread_mutex_lock(&mutex);//加锁

        while(isempty())//货架空，消费者等待生产者生产
        {
            pthread_cond_wait(&_consumerCond,&mutex);
        }
        *out = _q.front();
        _q.pop();
        //一定有空闲，唤醒生产者

        //......
        //这里可以加唤醒策略，
        // if(_q.size() < _cap/2)
        pthread_cond_signal(&_productorCond);

        pthread_mutex_unlock(&mutex);//解锁
    }
    ~queue_block()
    {
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&_consumerCond);
        pthread_cond_destroy(&_productorCond);

    }


private:
    std::queue<T> _q;
    int _cap;
    pthread_mutex_t mutex;
    pthread_cond_t _consumerCond;
    pthread_cond_t _productorCond;

};


